///////////////////////////////////////////////////////////////////////////////
// File:        TcpServer.cc
// Author:      671643387@qq.com
// Description:
///////////////////////////////////////////////////////////////////////////////

#include <cassert>
#include "common/TcpServer.hpp"
using namespace monkey::common;

///////////////////////////////////////////////////////////////////////////////

TcpServer::TcpServer(int worker)
    : server_(pio_server_new())
{
    assert(server_);

    pio_server_config_worker(server_, worker);
    pio_server_set_connection_establised_fn(server_, 
        &TcpServer::_AcceptNewConnection, this);
}

TcpServer::~TcpServer(void)
{
    if (server_)
        pio_server_free(server_);
}

bool TcpServer::Open(std::string address, short port, int backlog)
{
    return (0 == pio_server_open(server_, address.c_str(), port, backlog));
}

void TcpServer::Stop(void)
{
    pio_server_stop(server_);
}

///////////////////////////////////////////////////////////////////////////////

void TcpServer::OnAcceptNewConnection(TcpConnection* conn)
{
    // default
    conn->Close();
}

///////////////////////////////////////////////////////////////////////////////

TcpConnection* TcpServer::MallocConnection(struct pio_connection* conn)
{
    assert(conn);
    TcpConnection* newconn = new TcpConnection();
    if (newconn)
        newconn->_InitConnection(conn, this);
    return newconn;
}

void TcpServer::FreeConnection(TcpConnection* conn)
{
    assert(conn);
    delete conn;
}

///////////////////////////////////////////////////////////////////////////////

void TcpServer::_AcceptNewConnection(struct pio_connection* conn, void* arg)
{
    assert(conn && arg);
    TcpServer* pServ = static_cast<TcpServer*>(arg);
    TcpConnection* pConn = pServ->MallocConnection(conn);
    if (pConn)
    {
        pio_connection_set_read_fn(conn, &TcpConnection::_OnRead, pConn);
        pio_connection_set_write_fn(conn, &TcpConnection::_OnWrite, pConn);
        pio_connection_set_close_fn(conn, &TcpConnection::_OnClose, pConn);
        pio_connection_set_userdata(conn, pConn);
        pServ->OnAcceptNewConnection(pConn);
    }
    else
        pio_connection_close(conn);
}